﻿using System;
using System.Collections.Generic;
using FairyGUI.Drawing;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ms.Util;

namespace FairyGUI
{
    /// <summary>
    /// 
    /// </summary>
    public class DynamicFont : BaseFont
    {
        SpriteFont _font;
        int _size;
        float _ascent;
        float _lineHeight;
        float _scale;
        TextFormat _format;
        FontStyle _style;
        bool _boldVertice;
        SpriteFont.Glyph _char;
        SpriteFont.Glyph _lineChar;
        bool _gotLineChar;

        static Dictionary<int, SpriteFont> sFontCache = new Dictionary<int, SpriteFont>();

        public override Color color => _format?.color?? Color.White;
        public override float scale => _scale;
        public DynamicFont()
        {
            this.canTint = true;
            this.keepCrisp = true;
            this.customOutline = true;
        }

        public DynamicFont(string name, SpriteFont font) : this()
        {
            this.name = name;
            this.nativeFont = font;
        }

        public SpriteFont nativeFont
        {
            get { return _font; }
            set
            {
                _font = value;

                if (mainTexture != null)
                    mainTexture.Dispose();
                mainTexture = new NTexture(_font.Texture);

                // _ascent = _font.ascent;
                // _lineHeight = _font.lineHeight;
                _ascent = SpriteFontEX.fontSize;
                _lineHeight = SpriteFontEX.fontSize * 1.25f;
            }
        }

        override public void SetFormat(TextFormat format, float fontSizeScale)
        {
            /*_format = format;
			if (fontSizeScale == 1)
				_size = format.size;
			else
				_size = (int)Math.Floor((float)format.size * fontSizeScale);

			_style = FontStyle.Regular;
			if (format.bold)
				_style |= FontStyle.Bold;
			if (format.italic)
				_style |= FontStyle.Italic;
			if (format.underline)
				_style |= FontStyle.Underline;*/

            _format = format;
            float size = format.size * fontSizeScale;
            if (keepCrisp)
                size *= UIContentScaler.scaleFactor;
            if (_format.specialStyle == TextFormat.SpecialStyle.Subscript || _format.specialStyle == TextFormat.SpecialStyle.Superscript)
                size *= SupScale;
            _size = Mathf.FloorToInt(size);
            if (_size == 0)
                _size = 1;
            _scale = (float)_size / SpriteFontEX.fontSize;

            if (format.bold && !customBold)
            {
                if (format.italic)
                {
                    if (customBoldAndItalic)
                        _style = FontStyle.Italic;
                    else
                        _style = FontStyle.BoldAndItalic;
                }
                else
                    _style = FontStyle.Bold;
            }
            else
            {
                if (format.italic)
                    _style = FontStyle.Italic;
                else
                    _style = FontStyle.Normal;
            }

            if (format.underline)
                _style |= FontStyle.Underline;

            _boldVertice = format.bold && (customBold || (format.italic && customBoldAndItalic));
            //format.FillVertexColors(vertexColors);
        }

        public SpriteFont GetNativeFont(bool applyGlobalScale)
        {
            int size = applyGlobalScale ? (int)Math.Floor(_size * UIContentScaler.scaleFactor) : _size;

            int key = (size << 16) + (int)_style;
            SpriteFont result;
            if (!sFontCache.TryGetValue(key, out result))
            {
                result = SpriteFontEX.InitChineseFont(SpriteFontEX.fontSize);
                //result = new Font(this.name, size, _style, GraphicsUnit.Pixel);
                sFontCache[key] = result;
            }

            return result;
        }

        Dictionary<char, SpriteFont.Glyph> char_Glyph_Dict;
        Dictionary<char, SpriteFont.Glyph> Char_Glyph_Dict => char_Glyph_Dict ?? (char_Glyph_Dict = _font.GetGlyphs());

        public override bool GetGlyph(char ch, out float width, out float height, out float baseline)
        {

            if (!Char_Glyph_Dict.TryGetValue(ch, out var _char))
            {
                width = height = baseline = 0;
                return false;
            }

            width = _char.WidthIncludingBearings;
            height = _lineHeight * _scale;
            baseline = (_lineHeight - _ascent) * _scale;//todo monogame positive y is down, however unity is up
            if (_boldVertice)
                width++;

            if (_format.specialStyle == TextFormat.SpecialStyle.Subscript)
            {
                height /= SupScale;
                baseline /= SupScale;
            }
            else if (_format.specialStyle == TextFormat.SpecialStyle.Superscript)
            {
                height = height / SupScale + baseline * SupOffset;
                baseline *= (SupOffset + 1 / SupScale);
            }

            height = Mathf.RoundToInt(height);
            baseline = Mathf.RoundToInt(baseline);

            if (keepCrisp)
            {
                width /= UIContentScaler.scaleFactor;
                height /= UIContentScaler.scaleFactor;
                baseline /= UIContentScaler.scaleFactor;
            }
            AppDebug.Log($"char:{ch}\t _scale:{_scale}\t fontColor:{_format.color}\t fontSize:{SpriteFontEX.fontSize}\t _lineHeight:{_lineHeight}\t width:{width}\t height:{height}\t baseline:{baseline} ");
            return true;
        }

        public override bool HasCharacter(char ch)
        {
            return Char_Glyph_Dict?.ContainsKey(ch) ?? false;
        }
        public override int GetLineHeight(int size)
        {
            return Mathf.RoundToInt(_lineHeight * size / SpriteFontEX.fontSize);
        }
    }
}
